# import os
# import sys
# import pandas as pd
#
# # ✅ 设置项目根目录路径并加入 sys.path
# BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))
# if BASE_DIR not in sys.path:
#     sys.path.insert(0, BASE_DIR)
#
# # ✅ 导入归一化与分箱模块
# from src.normalization.normalize_indicators import normalize_indicators
# from src.normalization.bin_indicators import bin_indicators
#
# # 📂 数据目录与输入路径
# data_dir = os.path.join(BASE_DIR, "data", "3_indicator_normalization")
# input_file = os.path.join(data_dir, "indicators_filled.csv")
#
# # ✅ 用户选择归一化方法
# print("🎯 请选择归一化方法：")
# print("1️⃣ Min-Max 归一化")
# print("2️⃣ RobustScaler 归一化")
# print("3️⃣ 动态归一化（根据变异系数自动选择）")
# norm_choice = input("👉 请输入对应数字（1/2/3）进行选择：").strip()
#
# norm_method_map = {'1': 'minmax', '2': 'robust', '3': 'dynamic'}
# if norm_choice not in norm_method_map:
#     print("❌ 输入无效，请重新运行程序并选择 1、2 或 3。")
#     sys.exit(1)
#
# selected_norm_method = norm_method_map[norm_choice]
# print(f"\n✅ 已选择归一化方法：{selected_norm_method}\n")
#
# # ✅ 用户选择分箱方法
# print("🎯 请选择分箱方法：")
# print("1️⃣ 等频分箱（quantile）")
# print("2️⃣ 等距分箱（uniform）")
# print("3️⃣ 聚类分箱（kmeans）")
# print("4️⃣ 标准差分箱（std_dev）")
# bin_choice = input("👉 请输入对应数字（1/2/3/4）进行选择：").strip()
#
# bin_method_map = {'1': 'quantile', '2': 'uniform', '3': 'kmeans', '4': 'std_dev'}
# if bin_choice not in bin_method_map:
#     print("❌ 输入无效，请重新运行程序并选择 1、2、3 或 4。")
#     sys.exit(1)
#
# selected_bin_method = bin_method_map[bin_choice]
# print(f"\n✅ 已选择分箱方法：{selected_bin_method}\n")
#
# # ✅ 步骤1：读取数据
# df = pd.read_csv(input_file)
#
# # ✅ 步骤2：归一化（带方法记录）
# df_normalized, method_record = normalize_indicators(df, method=selected_norm_method)
#
# # ✅ 步骤3：导出归一化结果
# norm_output = os.path.join(data_dir, f"indicators_normalized_{selected_norm_method}.csv")
# method_output = os.path.join(data_dir, f"indicator_normalization_method_{selected_norm_method}.csv")
#
# df_normalized.to_csv(norm_output, index=False, encoding='utf-8-sig')
# pd.DataFrame.from_dict(method_record, orient='index', columns=['normalize_method']).to_csv(
#     method_output, encoding='utf-8-sig'
# )
#
# print(f"📁 已保存归一化结果文件：{norm_output}")
# print(f"📁 已保存归一化方法记录：{method_output}")
#
# # ✅ 步骤4：分箱
# df_binned, bin_metadata = bin_indicators(df_normalized, bins=7, method=selected_bin_method)
# bin_output = os.path.join(data_dir, f"indicators_binned_{selected_norm_method}_{selected_bin_method}.csv")
# meta_output = os.path.join(data_dir, f"indicator_bin_metadata_{selected_norm_method}_{selected_bin_method}.csv")
#
# df_binned.to_csv(bin_output, index=False, encoding='utf-8-sig')
# bin_metadata.to_csv(meta_output, index=False, encoding='utf-8-sig')
#
# print(f"\n📁 已保存分箱数据：{bin_output}")
# print(f"📁 已保存分箱元数据：{meta_output}")
# print("\n🎉 指标归一化与分箱分类流程全部完成！感谢使用 openDBER 🙌")



import os
import sys
import pandas as pd
import json
import matplotlib.pyplot as plt

import matplotlib

# ---- 中文字体设置 ----
matplotlib.rcParams['font.sans-serif'] = ['SimHei']   # 或 ['Microsoft YaHei']
matplotlib.rcParams['axes.unicode_minus'] = False
# ---------------------

# ✅ 设置项目根目录路径并加入 sys.path
BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))
if BASE_DIR not in sys.path:
    sys.path.insert(0, BASE_DIR)

# ✅ 导入归一化与分箱模块
from src.normalization.normalize_indicators import normalize_indicators
from src.normalization.bin_indicators import bin_indicators

# 📂 数据目录与输入路径
data_dir = os.path.join(BASE_DIR, "data", "3_indicator_normalization")
input_file = os.path.join(data_dir, "indicators_filled.csv")

# ⚙️ 参数配置：支持默认参数加载与 JSON 文件持久化
config_file = os.path.join(data_dir, "norm_binning_config.json")
selected_norm_method = None
selected_bin_method = None
bins_count = 7        # 默认分箱数
cv_threshold = 1.0    # 默认动态归一化 CV 阈值
if os.path.exists(config_file):
    # 📝 存在配置文件则直接使用其中参数，跳过手动选择
    with open(config_file, 'r', encoding='utf-8') as f:
        config = json.load(f)
    selected_norm_method = config.get('norm_method', 'robust')
    selected_bin_method = config.get('bin_method', 'quantile')
    bins_count = config.get('bins', 7)
    cv_threshold = config.get('cv_threshold', 1.0)
    print(f"🔧 检测到配置文件，使用默认参数：归一化方法 = {selected_norm_method}，分箱方法 = {selected_bin_method}，bins = {bins_count}，CV阈值 = {cv_threshold}\n")
else:
    # ✅ 用户选择归一化方法
    print("🎯 请选择归一化方法：")
    print("1️⃣ Min-Max 归一化")
    print("2️⃣ RobustScaler 归一化")
    print("3️⃣ 动态归一化（根据变异系数自动选择）")
    print("4️⃣ Z-score 标准化")
    norm_choice = input("👉 请输入对应数字（1/2/3/4）进行选择：").strip()
    norm_method_map = {'1': 'minmax', '2': 'robust', '3': 'dynamic', '4': 'zscore'}
    if norm_choice not in norm_method_map:
        print("❌ 输入无效，请重新运行程序并选择正确的编号。")
        sys.exit(1)
    selected_norm_method = norm_method_map[norm_choice]
    print(f"\n✅ 已选择归一化方法：{selected_norm_method}\n")

    # ✅ 用户选择分箱方法
    print("🎯 请选择分箱方法：")
    print("1️⃣ 等频分箱（quantile）")
    print("2️⃣ 等距分箱（uniform）")
    print("3️⃣ 聚类分箱（kmeans）")
    print("4️⃣ 标准差分箱（std_dev）")
    bin_choice = input("👉 请输入对应数字（1/2/3/4）进行选择：").strip()
    bin_method_map = {'1': 'quantile', '2': 'uniform', '3': 'kmeans', '4': 'std_dev'}
    if bin_choice not in bin_method_map:
        print("❌ 输入无效，请重新运行程序并选择正确的编号。")
        sys.exit(1)
    selected_bin_method = bin_method_map[bin_choice]
    print(f"\n✅ 已选择分箱方法：{selected_bin_method}\n")

    # ⚙️ 将所选参数保存至 JSON 配置文件，供下次运行默认使用
    config = {
        'norm_method': selected_norm_method,
        'bin_method': selected_bin_method,
        'bins': bins_count,
        'cv_threshold': cv_threshold
    }
    with open(config_file, 'w', encoding='utf-8') as f:
        json.dump(config, f, ensure_ascii=False, indent=4)
    print(f"💾 已保存参数配置到文件：{config_file}\n")


# ✅ 步骤1：读取预处理后的指标数据
df = pd.read_csv(input_file)

# ✅ 步骤2：执行归一化（并记录所用方法）
df_normalized, method_record = normalize_indicators(df, method=selected_norm_method, cv_threshold=cv_threshold)

# ✅ 步骤3：导出归一化结果及方法记录
norm_output = os.path.join(data_dir, f"indicators_normalized_{selected_norm_method}.csv")
method_output = os.path.join(data_dir, f"indicator_normalization_method_{selected_norm_method}.csv")

df_normalized.to_csv(norm_output, index=False, encoding='utf-8-sig')
pd.DataFrame.from_dict(method_record, orient='index', columns=['normalize_method']).to_csv(
    method_output, encoding='utf-8-sig'
)

print(f"📁 已保存归一化结果文件：{norm_output}")
print(f"📁 已保存归一化方法记录：{method_output}")

# ✅ 步骤4：执行分箱
df_binned, bin_metadata = bin_indicators(df_normalized, bins=bins_count, method=selected_bin_method)
bin_output = os.path.join(data_dir, f"indicators_binned_{selected_norm_method}_{selected_bin_method}.csv")
meta_output = os.path.join(data_dir, f"indicator_bin_metadata_{selected_norm_method}_{selected_bin_method}.csv")

df_binned.to_csv(bin_output, index=False, encoding='utf-8-sig')
bin_metadata.to_csv(meta_output, index=False, encoding='utf-8-sig')

print(f"📁 已保存分箱数据：{bin_output}")
print(f"📁 已保存分箱元数据：{meta_output}")

# ✅ 步骤5：生成每个指标的分布直方图（叠加红线显示分箱边界）
hist_dir = os.path.join(data_dir, "bin_histograms")
os.makedirs(hist_dir, exist_ok=True)
for _, row in bin_metadata.iterrows():
    indicator = row['indicator']
    edges = row['edges']
    series_vals = df_normalized[indicator]
    plt.figure()
    plt.hist(series_vals, bins=30, color='skyblue', edgecolor='black')
    # 绘制分箱边界为红色虚线
    for edge in edges:
        plt.axvline(x=edge, color='red', linestyle='--', linewidth=1)
    plt.title(f"{indicator} - 分布直方图 (含分箱边界)")
    plt.xlabel("指标值")
    plt.ylabel("频数")
    # 保存图表文件
    plot_path = os.path.join(hist_dir, f"{indicator}_{selected_bin_method}_hist.png")
    plt.savefig(plot_path)
    plt.close()
    print(f"📊 已生成 {indicator} 的直方图: {plot_path}")

print("\n🎉 指标归一化与分箱流程全部完成！感谢使用 openDBER 🙌")
